<template>
  <FormModal
    title="json"
    keyboard
    wrapClassName="replace-modal"
    width="100vw"
    :centered="false"
    :mask="false"
    v-model:modelValue="modalVisible"
  >
    <div class="content">
      <div class="input-wrapper">
        <a-textarea
          v-model:value="jsonCode"
          :auto-size="{ minRows: 3, maxRows: 3 }"
        />
      </div>
      <div class="content-bottom">
        <div class="code-wrapper">
          <!-- <JsonViewer
            :value="displayJsonCode"
            copyable
            boxed
            sort
            :expand-depth="3"
            theme="dark"
          /> -->
          <!-- <vue-json-pretty showIcon showLineNumber :showDoubleQuotes="false" :data="displayJsonCode"  /> -->
          <a-table
            sticky
            rowKey="value"
            :pagination="false"
            :columns="displayJsonColumns"
            :dataSource="displayJsonCode"
          />
        </div>
        <div class="table-wrapper">
          <a-table
            sticky
            defaultExpandAllRows
            :pagination="false"
            rowKey="beforeKey"
            :columns="columns"
            :dataSource="dataSource"
          >
            <template #bodyCell="{ column, record }">
              <template v-if="column.dataIndex === '_action'">
                <span v-if="!record.children"></span>
                <a-button
                  v-else
                  type="link"
                  @click="handleReplaceSubField(record)"
                  >匹配子节点</a-button
                >
              </template>
              <template v-if="column.dataIndex === 'afterKey'">
                <a-input v-model:value="record.afterKey" />
              </template>
            </template>
          </a-table>
        </div>
      </div>
    </div>
    <template #footer>
      <div class="flex-between">
        <div>
          <!-- <a-button @click="handleClose"> 取消 </a-button> -->
          <a-select
            v-model:value="resolveStrategy"
            style="margin-left: 25px; width: 100px"
          >
            <a-select-option
              v-for="strategy in resolveStrategyList"
              :key="strategy.type"
            >
              {{ strategy.type }}
            </a-select-option>
          </a-select>
        </div>
        <div>
          <a-button
            type="primary"
            style="margin-left: 25px"
            @click="replaceField"
          >
            字段匹配
          </a-button>
          <a-button type="primary" style="margin-left: 25px" @click="handleOk">
            字段替换
          </a-button>
        </div>
      </div>
    </template>
  </FormModal>
</template>

<script setup>
import { computed, ref, watchEffect } from "vue";
import { message } from "ant-design-vue";
import FormModal from "@/components/FormModal/index.vue";
import { cotainsStr } from "@/utils";
// import { JsonViewer } from "vue3-json-viewer";
// import "vue3-json-viewer/dist/vue3-json-viewer.css";
// import VueJsonPretty from "vue-json-pretty";
// import "vue-json-pretty/lib/styles.css";
// import CodeEditor from "@/components/CodeEditor/index.vue";
// import demoCode from "./test/test.json?raw";
const demoCode=''

const props = defineProps({
  modelValue: {
    type: Boolean,
    default: false,
  },
  metaData: {
    type: Object,
    default: () => [],
  },
});
const emit = defineEmits(["update:modelValue", "replaceFieldList"]);

const modalVisible = computed({
  get() {
    return props.modelValue;
  },
  set(val) {
    if (!val) {
      jsonCode.value = demoCode;
    }
    emit("update:modelValue", val);
  },
});

const resolveStrategy = ref("yapi");
const resolveStrategyList = ref([
  {
    type: "yapi",
    resolve(jsonCodeObj) {
      let { properties } = jsonCodeObj;
      // 接口提出响应体接口，取真实字段
      if (
        properties &&
        Object.keys(properties).length == 3 &&
        properties.status
      ) {
        properties = properties.data.properties;
      }
      let arr = [];
      function visitProperties(properties, arr) {
        for (const key of Object.keys(properties)) {
          const item = properties[key];
          const field = {
            label: item.description,
            afterKey: key,
          };
          if (item.type === "array" || item.type === "object") {
            field.children = [];
            visitProperties(
              item.type === "array" ? item.items.properties : item.properties,
              field.children
            );
          }
          arr.push(field);
        }
      }
      visitProperties(properties, arr);
      return arr;
    },
    displayJSON(jsonCodeObj) {
      let { properties = {} } = jsonCodeObj;
      // 接口提出响应体接口，取真实字段
      if (
        properties &&
        Object.keys(properties).length == 3 &&
        properties.status
      ) {
        properties = properties.data.properties;
      }
      let dataSource = [];
      function visitProperties(properties, dataSource) {
        for (const key of Object.keys(properties)) {
          const item = properties[key];
          const data = {
            label: item.description,
            value: key,
          };
          if (item.description) {
            if (item.type === "array") {
              data.children = [];
            }
            dataSource.push(data);
          }
          if (item.type === "array") {
            visitProperties(
              item.items.properties,
              item.description ? data.children : dataSource
            );
          }
        }
      }
      visitProperties(properties, dataSource);
      console.log("🚀 ~ dataSource:", dataSource);
      return dataSource;
    },
  },
  {
    type: "json",
    resolve(jsonCodeObj) {
      return Object.keys(jsonCodeObj).map((key) => ({
        label: key,
        afterKey: jsonCodeObj[key],
      }));
    },
    displayJSON(jsonCodeObj) {
      return jsonCodeObj;
    },
  },
]);

const jsonCode = ref(demoCode);
const displayJsonColumns = [
  {
    title: "字段",
    dataIndex: "label",
    width: 150,
  },
  {
    title: "key",
    dataIndex: "value",
    width: 150,
  },
];
const displayJsonCode = computed(() => {
  const resolveStrategyObj = resolveStrategyList.value.find(
    (strategy) => strategy.type === resolveStrategy.value
  );
  return resolveStrategyObj.displayJSON(JSON.parse(jsonCode.value || "{}"));
});

const columns = ref([
  {
    title: "字段",
    dataIndex: "label",
  },
  {
    title: "替换前key",
    dataIndex: "beforeKey",
  },
  {
    title: "替换后key",
    dataIndex: "afterKey",
  },
  {
    title: "操作",
    dataIndex: "_action",
    width: 150,
  },
]);

const dataSource = ref([]);

watchEffect(() => {
  function mapField(field) {
    const result = {
      ...field,
      afterKey: "",
    };
    if (field.children) {
      result.children = field.children.map(mapField);
    }
    return result;
  }
  dataSource.value = props.metaData.map((field) => mapField(field));
});

function findFieldByFun(arr, field, strategy) {
  let result = null;
  for (let index = 0; index < arr.length; index++) {
    const item = arr[index];
    result = strategy(item, field);
    if (result) {
      // 优化，将匹配中的元删除
      if (!item.children) {
        arr.splice(index, 1);
      }
      break;
    }
  }
  return result;
}
function replaceFieldKey(dataSource, propertiesList) {
  for (const field of dataSource) {
    let result = findFieldByFun(propertiesList, field, (sreverField, b) => {
      return sreverField.label === b.label ? sreverField : null;
    });
    if (!result) {
      result = findFieldByFun(propertiesList, field, (sreverField, b) => {
        let flag = cotainsStr(sreverField.label, b.label);
        if (flag) {
          const item = dataSource.find(
            (data) => data.label === sreverField.label
          );
          flag = flag && !item;
        }
        return flag ? sreverField : null;
      });
    }
    if (result) {
      field.afterKey = result.afterKey;
      if (field.children) {
        replaceFieldKey(field.children, result.children);
      }
    } else {
      unMatcheCount.value++;
      if (field.children) {
        unMatcheCount.value += field.children.length;
      }
    }
  }
}
const unMatcheCount = ref(0);
function replaceField() {
  if (!jsonCode.value) {
    return message.warn("请先在左侧输入需要匹配的数据源");
  }
  try {
    unMatcheCount.value = 0;
    const data = JSON.parse(jsonCode.value);
    const resolveStrategyObj = resolveStrategyList.value.find(
      (strategy) => strategy.type === resolveStrategy.value
    );
    const propertiesList = resolveStrategyObj.resolve(data);
    replaceFieldKey(dataSource.value, propertiesList);
    if (unMatcheCount.value > 0) {
      message.warn(`还有${unMatcheCount.value}项没有匹配成功`);
      unMatcheCount.value = 0;
    }
  } catch (e) {
    console.log("parse jsonCode error,", e);
    message.warn("输入的数据源不是json格式，请检查后重试!");
  }
}

function handleReplaceSubField(field) {
  if (!field.afterKey) {
    message.warn("请先匹配当前节点!");
    return;
  }
  if (!jsonCode.value) {
    return message.warn("请先在左侧输入需要匹配的数据源");
  }
  try {
    unMatcheCount.value = 0;
    const data = JSON.parse(jsonCode.value);
    const resolveStrategyObj = resolveStrategyList.value.find(
      (strategy) => strategy.type === resolveStrategy.value
    );
    const propertiesList = resolveStrategyObj.resolve(data);
    const { afterKey, children } = field;
    const serverField = propertiesList.find(
      (item) => item.afterKey === afterKey
    );
    replaceFieldKey(children, serverField.children)
    if (unMatcheCount.value > 0) {
      message.warn(`当前节点还有${unMatcheCount.value}项没有匹配成功`);
      unMatcheCount.value = 0;
    }
  } catch (e) {
    console.log("parse jsonCode error,", e);
    message.warn("输入的数据源不是json格式，请检查后重试!");
  }
}

function handleClose() {
  modalVisible.value = false;
}

function handleOk() {
  emit("replaceFieldList", [...dataSource.value]);
  handleClose();
}
</script>

<style lang="less" scoped>
:deep(.ant-modal-body) {
  padding: 0 !important;
}
.flex-between {
  display: flex;
  justify-content: space-between;
}
// :deep(.jv-container .jv-code.boxed) {
//   max-height: 500px;
// }
// .content {
//   display: flex;
// }
.content-bottom {
  display: flex;
  margin-top: 20px;
}
.code-wrapper {
  margin-right: 30px;
  flex: 0 0 40%;
  height: calc(100vh - 220px);
  overflow-y: auto;
}
.table-wrapper {
  flex: 0 0 60%;
   height: calc(100vh - 220px);
  overflow-y: auto;
}
</style>
<style lang="less">
.replace-modal {
  overflow: hidden !important;
  .ant-modal {
    max-width: 100vw;
    transform-origin: 0 0 !important;
    top: 0px !important;
  }
  .ant-modal-body {
    height: calc(100vh - 120px);
  }
}
</style>
